package relu.fbs;

import java.util.*;

import jfm.model.Types.CropType;

/** Collection of pre-defined lists of crops and mappings from FBS to JFM data */
public abstract class FarmData {

	/** Maps from a JFM crop to a list of actual LP model croptypes required to represent it*/
	public static Map<CropType,HashSet<CropType>> jfmToLPMap = new LinkedHashMap<CropType,HashSet<CropType>>();
	/** Maps from a croptype to its set aside equivalent */
	public static Map<CropType,CropType> jfmSetAsideCrops = new LinkedHashMap<CropType,CropType>();
	/** Maps from a jfm crop type to a list of fbs croptypes */
	public static Map<CropType,HashSet<CropType>> jfmCropTypesMap=new LinkedHashMap<CropType,HashSet<CropType>>();
	/** Maps an fbs croptype to a jfm croptype */
	public static Map<CropType,CropType> mapToJFMCrop=new LinkedHashMap<CropType,CropType>();

	public static Set<CropType> jfmCombinableCrops = new LinkedHashSet<CropType>();
	public static Set<CropType> jfmNegativeListCrops = new LinkedHashSet<CropType>();
	public static Set<CropType> jfmUnModelledCrops = new LinkedHashSet<CropType>();
	public static Set<CropType> jfmModelledCrops = new LinkedHashSet<CropType>(); // The three above sum to form this set 
	
	private static void jfmToLPMapAdd(CropType jfm,CropType lp){
		if ( !jfmToLPMap.containsKey(jfm)){
			jfmToLPMap.put(jfm,new LinkedHashSet<CropType>());
		}
		jfmToLPMap.get(jfm).add(lp);
	}
	
	private static void jfmAddTo(CropType to,CropType toadd){
		jfmCropTypesMap.get(to).add(toadd);
	}

	public static CropType getCheckedCropType(Integer code){
		if ( fbsCodeToCropType.containsKey(code)){
			return fbsCodeToCropType.get(code);
		} else {
			throw new Error("No crop with code "+code);
		}
	}
	
	/** Special Crop codes used for totals */
	public static Set<Integer> fbsTotalCodes=new HashSet<Integer>();
	/** Complete list of arable crop codes in the FBS */
	public static Map<Integer,CropType> fbsCodeToCropType=new HashMap<Integer,CropType>();
	static {
		jfmToLPMapAdd(CropType.FEEDBEANS,CropType.WINTERBEANS);
		jfmToLPMapAdd(CropType.FEEDBEANS,CropType.SPRINGBEANS);
//		jfmToLPMapAdd(CropType.FEEDBEANS,CropType.WINTERBEANSSA);
//		jfmToLPMapAdd(CropType.FEEDBEANS,CropType.SPRINGBEANSSA);
		fbsTotalCodes.add(299); // Main
		fbsTotalCodes.add(316); // Unknown total?
		
		fbsTotalCodes.add(408); // S Year Set Aside ?? S= Survey?
		fbsTotalCodes.add(410); // Total By Products and Forage
		fbsTotalCodes.add(414); // Set aside 1yr scheme
		fbsTotalCodes.add(418); // Forage
		fbsTotalCodes.add(419); // Compulsory Set aside
		fbsTotalCodes.add(420); // By Products
		fbsTotalCodes.add(421); // Non Rotational Set Aside
		fbsTotalCodes.add(422); // Set Aside
		fbsTotalCodes.add(424); // Uncropped Xcl Fallow and SetAside
		fbsTotalCodes.add(901); // Tranche??
		fbsTotalCodes.add(902); // Tranche??
		fbsTotalCodes.add(903); // Tranche??
		fbsTotalCodes.add(904); // Tranche??
		fbsTotalCodes.add(905); // Tranche??
		fbsTotalCodes.add(906); // Tranche??
		
		fbsCodeToCropType.put(1, CropType.WINTERWHEAT);
		fbsCodeToCropType.put(2, CropType.SPRINGWHEAT);
		fbsCodeToCropType.put(3, CropType.MIXEDWHEAT);
		fbsCodeToCropType.put(4, CropType.DURUMWHEAT);
		fbsCodeToCropType.put(5, CropType.TRITICALE);
		fbsCodeToCropType.put(11, CropType.WINTERBARLEY);
		fbsCodeToCropType.put(12, CropType.SPRINGBARLEY);
		fbsCodeToCropType.put(13, CropType.MIXEDBARLEY);
		fbsCodeToCropType.put(21, CropType.WINTEROATS);
		fbsCodeToCropType.put(22, CropType.SPRINGOATS);
		fbsCodeToCropType.put(23, CropType.MIXEDOATS);
		fbsCodeToCropType.put(31, CropType.RYE);
		fbsCodeToCropType.put(41, CropType.MIXEDCEREALS);
		fbsCodeToCropType.put(52, CropType.GRAINMAIZE);
		fbsCodeToCropType.put(61, CropType.FEEDBEANS);
		fbsCodeToCropType.put(62, CropType.FEEDPEAS);
		fbsCodeToCropType.put(63, CropType.DRIEDPEAS);
		fbsCodeToCropType.put(64, CropType.PROTEIN);
		fbsCodeToCropType.put(71, CropType.EARLYPOTATOES);
		fbsCodeToCropType.put(72, CropType.PROCPOTATOES);
		fbsCodeToCropType.put(73, CropType.WAREPOTATOES);
		fbsCodeToCropType.put(74, CropType.SEEDPOTATOES);
		fbsCodeToCropType.put(75, CropType.MIXEDPOTATOES);
		fbsCodeToCropType.put(81, CropType.SUGARBEET);
		fbsCodeToCropType.put(93, CropType.FLAX);
		fbsCodeToCropType.put(94, CropType.LINSEED);
		fbsCodeToCropType.put(91, CropType.WOSRNDL);
		fbsCodeToCropType.put(95, CropType.SOSRNDL);
		fbsCodeToCropType.put(96, CropType.WOSRDL);
		fbsCodeToCropType.put(97, CropType.SOSRDL);
		fbsCodeToCropType.put(98, CropType.OOSR);
		fbsCodeToCropType.put(92, CropType.OILSEEDS);
		fbsCodeToCropType.put(100, CropType.HEMP);
		fbsCodeToCropType.put(101, CropType.HOPS);
		fbsCodeToCropType.put(103, CropType.MEDICINALS);
		fbsCodeToCropType.put(104, CropType.HERBAGESEED);
		fbsCodeToCropType.put(106, CropType.OTHERARABLE);

		// VERY MISCELLANEOUS
		fbsCodeToCropType.put(85, CropType.SUGARBEETQUOTALEASED);
		fbsCodeToCropType.put(65, CropType.UNKNOWN);
		// Lump together a whole bunch of horticultural crops
		int[] freshveg ={109,127,131,132,133,134,135,136,137,138,139,
				140,141,142,143,
				144,145,146,147,148,149,150,151,152,153,154,155,156,
				157,158,146,148,150,151,
				159,160,161,162,163,164,165,166,167,168,169,170,171,
				172,173,175,176,177,178,179,180,181,170,171,173,174,176,179,180,181,
				231,233,234,235,250,251,253,254,255,256,257,258,260,261,262,263,264};
		for(int i=0;i<freshveg.length;i++){
			fbsCodeToCropType.put(freshveg[i], CropType.FRESHFRUITANDVEG);
		}
		int[] nurseryandflowers={105,108,112,113,224,225,265,110,111,115,116,117,118,119,
				120,121,122,123,124,125,129,228,229};
		for(int i=0;i<nurseryandflowers.length;i++){
			fbsCodeToCropType.put(nurseryandflowers[i], CropType.NURSERYANDFLOWERS);
		}
		int[] fruitandberries={190,191,192,193,194,195,
				196,197,198,199,200,201,202,203,
				204,205,206,207,208,209,210,
				211,212,213,214,215,216,217,218,219,
				220,221,222,223,
				230,232,
				236,237,238,239,240,241,242,243,244,
				246,247,245
				};
		for(int i=0;i<fruitandberries.length;i++){
			fbsCodeToCropType.put(fruitandberries[i], CropType.ORCHARD);
		}		
		int[] grassandgrazing={402,403,404,405};
		for(int i=0;i<grassandgrazing.length;i++){
			fbsCodeToCropType.put(grassandgrazing[i], CropType.GRAZING);
		}
		int[] energy={99,107};
		for(int i=0;i<energy.length;i++){
			fbsCodeToCropType.put(energy[i], CropType.ENERGY);
		}		
		int[] fodder={400,401,415,416,417};
		for(int i=0;i<fodder.length;i++){
			fbsCodeToCropType.put(fodder[i], CropType.FODDER);
		}	
		int[] otherlu={406,407,409,411,412,413};
		for(int i=0;i<otherlu.length;i++){
			fbsCodeToCropType.put(otherlu[i], CropType.MISCLU);
		}	
		int[] byproducts={321,322,327,323,324,325,328,326};
		for(int i=0;i<byproducts.length;i++){
			fbsCodeToCropType.put(byproducts[i],CropType.BYPRODUCTS);
		}
		int[] processed={300,301,302,303,304,305};
		for ( int i=0;i<processed.length;i++){
			fbsCodeToCropType.put(processed[i], CropType.PROCESSED);
		}
		
		fbsCodeToCropType.put(126, CropType.MUSHROOMS);		
		
//		fbsCodeToCropType.put(422, CropType.SETASIDE);		
		
	
		// Include all set aside crops here including those we don't model 
		jfmSetAsideCrops.put(CropType.WOSR, CropType.WOSRSA);
		jfmSetAsideCrops.put(CropType.SOSR, CropType.SOSRSA);
		jfmSetAsideCrops.put(CropType.WINTERWHEAT, CropType.WINTERWHEATSA);
		jfmSetAsideCrops.put(CropType.SPRINGWHEAT, CropType.SPRINGWHEATSA);
		jfmSetAsideCrops.put(CropType.LINSEED, CropType.LINSEEDSA);
		jfmSetAsideCrops.put(CropType.SPRINGBARLEY, CropType.SPRINGBARLEYSA);
		jfmSetAsideCrops.put(CropType.WINTERBARLEY, CropType.WINTERBARLEYSA);
		jfmSetAsideCrops.put(CropType.FEEDBEANS, CropType.FEEDBEANSSA);
		jfmSetAsideCrops.put(CropType.MIXEDCEREALS, CropType.MIXEDCEREALSSA);
		jfmSetAsideCrops.put(CropType.OILSEEDS, CropType.OILSEEDSSA);
		jfmSetAsideCrops.put(CropType.MISC, CropType.MISCSA);
		jfmSetAsideCrops.put(CropType.OTHERARABLE, CropType.OTHERARABLESA);
		jfmSetAsideCrops.put(CropType.GRAZING, CropType.GRAZINGSA);
		jfmSetAsideCrops.put(CropType.FODDER, CropType.FODDERSA);
		jfmSetAsideCrops.put(CropType.ENERGY, CropType.ENERGYSA);
		
		// --- Now set up categories of crops that we can model in JFM  --- // 		
		jfmCombinableCrops.add(CropType.WINTERWHEAT);
		jfmCombinableCrops.add(CropType.SPRINGWHEAT);
		jfmCombinableCrops.add(CropType.WINTERBARLEY);
		jfmCombinableCrops.add(CropType.SPRINGBARLEY);
		jfmCombinableCrops.add(CropType.FEEDBEANS);
		jfmCombinableCrops.add(CropType.DRIEDPEAS);
		jfmCombinableCrops.add(CropType.WOSR);
		jfmCombinableCrops.add(CropType.LINSEED);
		jfmCombinableCrops.add(CropType.SOSR);
		jfmCombinableCrops.addAll(jfmSetAsideCrops.values());
		jfmCombinableCrops.remove(CropType.MISCSA);
		jfmCombinableCrops.remove(CropType.MIXEDCEREALSSA);
		jfmCombinableCrops.remove(CropType.OILSEEDSSA);
		jfmCombinableCrops.remove(CropType.OTHERARABLESA);
		jfmCombinableCrops.remove(CropType.GRAZINGSA);
		jfmCombinableCrops.remove(CropType.FODDERSA);
		jfmCombinableCrops.remove(CropType.ENERGYSA);
		
		jfmNegativeListCrops.add(CropType.WAREPOTATOES);
		jfmNegativeListCrops.add(CropType.SUGARBEET);
		
		jfmModelledCrops.addAll(jfmNegativeListCrops);
		jfmModelledCrops.addAll(jfmCombinableCrops);
		
		/* --- List of Crops that we identify in JFM .. 
		 * These are the crop categories that will appear as columns in jfm data files 
		 * The idea is to keep this list to a minimum so as to keep jfm data files manageable
		 * in size and relatively simple includes some that are not modelled -- */ 
		// These are the ones we can model
		jfmCropTypesMap.put(CropType.WINTERWHEAT, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.SPRINGWHEAT, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.SPRINGBARLEY, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.WINTERBARLEY, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.FEEDBEANS, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.DRIEDPEAS, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.WAREPOTATOES,new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.SUGARBEET,new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.LINSEED, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.WOSR, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.SOSR, new HashSet<CropType>());
		
		// These are the ones we cant model 
		jfmCropTypesMap.put(CropType.OILSEEDS, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.OTHERARABLE, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.MIXEDCEREALS, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.FRESHFRUITANDVEG, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.ORCHARD, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.MUSHROOMS, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.NURSERYANDFLOWERS, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.GRAZING, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.FODDER, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.ENERGY, new HashSet<CropType>());
		jfmCropTypesMap.put(CropType.MISC, new HashSet<CropType>());

		/* Make a list of the above */
		jfmUnModelledCrops.add(CropType.OILSEEDS);
		jfmUnModelledCrops.add(CropType.OILSEEDSSA);
		jfmUnModelledCrops.add(CropType.OTHERARABLE);
		jfmUnModelledCrops.add(CropType.OTHERARABLESA);
		jfmUnModelledCrops.add(CropType.MIXEDCEREALS);
		jfmUnModelledCrops.add(CropType.MIXEDCEREALSSA);
		jfmUnModelledCrops.add(CropType.FRESHFRUITANDVEG);
		jfmUnModelledCrops.add(CropType.ORCHARD);
		jfmUnModelledCrops.add(CropType.MUSHROOMS);
		jfmUnModelledCrops.add(CropType.NURSERYANDFLOWERS);
		jfmUnModelledCrops.add(CropType.FODDER);
		jfmUnModelledCrops.add(CropType.FODDERSA);
		jfmUnModelledCrops.add(CropType.GRAZING);
		jfmUnModelledCrops.add(CropType.GRAZINGSA);
		jfmUnModelledCrops.add(CropType.ENERGY);
		jfmUnModelledCrops.add(CropType.ENERGYSA);
		jfmUnModelledCrops.add(CropType.MISC);
		// Also include unmodelled crops on set aside
		jfmUnModelledCrops.add(CropType.MISCSA);
		jfmUnModelledCrops.add(CropType.MIXEDCEREALSSA);
		jfmUnModelledCrops.add(CropType.OILSEEDSSA);
		
		// Build Lists for Modelable Crops 
		jfmAddTo(CropType.WINTERWHEAT,CropType.WINTERWHEAT);		
		jfmAddTo(CropType.SPRINGWHEAT,CropType.SPRINGWHEAT);	
		jfmAddTo(CropType.SPRINGBARLEY,CropType.SPRINGBARLEY);
		jfmAddTo(CropType.WINTERBARLEY,CropType.WINTERBARLEY);
		jfmAddTo(CropType.FEEDBEANS,CropType.FEEDBEANS);
		jfmAddTo(CropType.DRIEDPEAS,CropType.FEEDPEAS);
		jfmAddTo(CropType.DRIEDPEAS,CropType.DRIEDPEAS);
		jfmAddTo(CropType.WAREPOTATOES,CropType.WAREPOTATOES);
		jfmAddTo(CropType.SUGARBEET,CropType.SUGARBEET);
		jfmAddTo(CropType.LINSEED,CropType.LINSEED);		
		jfmAddTo(CropType.WOSR,CropType.WOSRDL);
		jfmAddTo(CropType.WOSR,CropType.WOSRNDL);
		jfmAddTo(CropType.SOSR,CropType.SOSRDL);
		jfmAddTo(CropType.SOSR,CropType.SOSRNDL);
		
		// Build Lists for unmodelable crops 
		jfmAddTo(CropType.OTHERARABLE,CropType.EARLYPOTATOES);
		jfmAddTo(CropType.OTHERARABLE,CropType.PROCPOTATOES);
		jfmAddTo(CropType.OTHERARABLE,CropType.SEEDPOTATOES);
		jfmAddTo(CropType.OTHERARABLE,CropType.MIXEDPOTATOES);
		jfmAddTo(CropType.OTHERARABLE,CropType.FLAX);	
		jfmAddTo(CropType.OTHERARABLE,CropType.PROTEIN);
		jfmAddTo(CropType.OTHERARABLE,CropType.HEMP);
		jfmAddTo(CropType.OTHERARABLE,CropType.MEDICINALS);
		jfmAddTo(CropType.OTHERARABLE,CropType.HOPS);
		jfmAddTo(CropType.OTHERARABLE,CropType.HERBAGESEED);
		jfmAddTo(CropType.OTHERARABLE,CropType.OTHERARABLE);		
		jfmAddTo(CropType.MIXEDCEREALS,CropType.MIXEDWHEAT);	
		jfmAddTo(CropType.MIXEDCEREALS,CropType.DURUMWHEAT);
		jfmAddTo(CropType.MIXEDCEREALS,CropType.TRITICALE);
		jfmAddTo(CropType.MIXEDCEREALS,CropType.MIXEDBARLEY);
		jfmAddTo(CropType.MIXEDCEREALS,CropType.WINTEROATS);
		jfmAddTo(CropType.MIXEDCEREALS,CropType.SPRINGOATS);
		jfmAddTo(CropType.MIXEDCEREALS,CropType.MIXEDOATS);
		jfmAddTo(CropType.MIXEDCEREALS,CropType.RYE);
		jfmAddTo(CropType.MIXEDCEREALS,CropType.MIXEDCEREALS);		
		jfmAddTo(CropType.MIXEDCEREALS,CropType.GRAINMAIZE);		
		jfmAddTo(CropType.OILSEEDS,CropType.OOSR);
		jfmAddTo(CropType.OILSEEDS,CropType.OILSEEDS);		
		jfmAddTo(CropType.FRESHFRUITANDVEG,CropType.FRESHFRUITANDVEG);		
		jfmAddTo(CropType.ORCHARD,CropType.ORCHARD);		
		jfmAddTo(CropType.MUSHROOMS,CropType.MUSHROOMS);		
		jfmAddTo(CropType.NURSERYANDFLOWERS,CropType.NURSERYANDFLOWERS);		
		jfmAddTo(CropType.GRAZING,CropType.GRAZING);
		jfmAddTo(CropType.FODDER,CropType.FODDER);
		jfmAddTo(CropType.ENERGY,CropType.ENERGY);	
		jfmAddTo(CropType.MISC,CropType.SUGARBEETQUOTALEASED);
		jfmAddTo(CropType.MISC,CropType.UNKNOWN);
		jfmAddTo(CropType.MISC,CropType.MISCLU);
		jfmAddTo(CropType.MISC,CropType.BYPRODUCTS);
		jfmAddTo(CropType.MISC,CropType.PROCESSED);
		
		for(Map.Entry<CropType, HashSet<CropType>> ent:jfmCropTypesMap.entrySet()){
			for ( CropType fbsct:ent.getValue()){
				if ( mapToJFMCrop.containsKey(fbsct)){
					throw new Error("No duplicates allowed");
				}
				mapToJFMCrop.put(fbsct,ent.getKey() );
			}
		}
		
	}

	public static Set<CropType> fbsCropsKeySet=new LinkedHashSet<CropType>(fbsCodeToCropType.values());
	
}
